using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using GraphEditor.Runtime;
using UnityEditor;
using UnityEngine;

namespace GraphEditor.Editor
{
    //[CustomEditor(typeof(GraphCanvas))]
    public class GraphCanvasEditor : UnityEditor.Editor
    {
        // --- 静态类型缓存 (和之前一样) ---
        private static List<Type> s_graphModelTypes;
        private static List<string> s_graphModelTypeFullNames; // 只用FullName列表即可

        // --- SerializedProperties ---
        private SerializedProperty _runtimeTypeProp;
        private SerializedProperty _runtimeDataProp;
        private SerializedProperty _exposedReferencesProp;

        // --- 编辑器状态变量 ---
        private string _runtimeTypeSearchInput = "";
        private Vector2 _suggestionsScrollPos;
        private bool _isFirstFrame = true;

        [InitializeOnLoadMethod]
        private static void InitializeTypeCache()
        {
            if (s_graphModelTypes != null) return;

            s_graphModelTypes = new List<Type>();
            var baseType = typeof(IElement);

            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                try
                {
                    s_graphModelTypes.AddRange(assembly.GetTypes().Where(t =>
                        t.IsClass && !t.IsAbstract && baseType.IsAssignableFrom(t)
                    ));
                }
                catch (ReflectionTypeLoadException) { /* 忽略 */ }
            }

            s_graphModelTypeFullNames = s_graphModelTypes.Select(t => t.FullName).OrderBy(name => name).ToList();
        }

        private void OnEnable()
        {
            _runtimeTypeProp = serializedObject.FindProperty("_runtimeType");
            _runtimeDataProp = serializedObject.FindProperty("_runtimeData");
            _exposedReferencesProp = serializedObject.FindProperty("exposedReferences");

            // 初始化搜索框的文本为当前属性的值
            _runtimeTypeSearchInput = _runtimeTypeProp.stringValue;
            _isFirstFrame = true;
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            // 在第一次绘制时，确保搜索框文本与属性同步
            if (_isFirstFrame)
            {
                _runtimeTypeSearchInput = _runtimeTypeProp.stringValue;
                _isFirstFrame = false;
            }

            DrawRuntimeTypeField();

            EditorGUILayout.Space();

            EditorGUILayout.LabelField("Data", EditorStyles.boldLabel);
            EditorGUILayout.PropertyField(_runtimeDataProp);
            EditorGUILayout.PropertyField(_exposedReferencesProp, true);

            serializedObject.ApplyModifiedProperties();
        }

        private void DrawRuntimeTypeField()
        {
            EditorGUILayout.LabelField("Configuration", EditorStyles.boldLabel);

            string currentTypeName = _runtimeTypeProp.stringValue;
            bool isTypeEmpty = string.IsNullOrEmpty(currentTypeName);
            bool isTypeValid = !isTypeEmpty && s_graphModelTypeFullNames.Contains(currentTypeName);

            // --- 1. 显示警告信息 ---
            if (isTypeEmpty)
            {
                EditorGUILayout.HelpBox("Runtime Type must be set.", MessageType.Warning);
            }
            else if (!isTypeValid)
            {
                EditorGUILayout.HelpBox($"Type '{currentTypeName}' not found. It may have been renamed or deleted.", MessageType.Error);
            }

            // --- 2. 绘制带按钮的输入框 ---
            // 定义控件名称以管理焦点
            const string controlName = "RuntimeTypeSearchField";

            EditorGUILayout.BeginHorizontal();

            // 文本输入框
            GUI.SetNextControlName(controlName);
            EditorGUI.BeginChangeCheck();
            _runtimeTypeSearchInput = EditorGUILayout.TextField("Runtime Type", _runtimeTypeSearchInput);
            if (EditorGUI.EndChangeCheck())
            {
                // 当用户手动输入完成时（例如按回车或失去焦点），更新属性
                _runtimeTypeProp.stringValue = _runtimeTypeSearchInput;
            }

            // “浏览全部”按钮
            if (GUILayout.Button("...", GUILayout.Width(30)))
            {
                ShowAllTypesMenu();
            }
            EditorGUILayout.EndHorizontal();

            // --- 3. 绘制模糊搜索的建议列表 ---
            // 只有当文本框被聚焦时才显示建议
            if (GUI.GetNameOfFocusedControl() == controlName && !string.IsNullOrEmpty(_runtimeTypeSearchInput))
            {
                // 执行模糊搜索 (这里用不区分大小写的Contains作为示例)
                var suggestions = s_graphModelTypeFullNames
                    .Where(fullName => fullName.IndexOf(_runtimeTypeSearchInput, StringComparison.OrdinalIgnoreCase) >= 0)
                    .Take(10) // 最多显示10条建议
                    .ToList();

                if (suggestions.Count > 0)
                {
                    // 在一个Box中绘制建议列表
                    EditorGUILayout.BeginVertical(GUI.skin.box);
                    _suggestionsScrollPos = EditorGUILayout.BeginScrollView(_suggestionsScrollPos, GUILayout.MaxHeight(150));

                    foreach (var suggestion in suggestions)
                    {
                        if (GUILayout.Button(suggestion, EditorStyles.label))
                        {
                            // 用户点击了一个建议
                            _runtimeTypeSearchInput = suggestion;
                            _runtimeTypeProp.stringValue = suggestion;

                            // 移除焦点以关闭建议列表
                            GUI.FocusControl(null);
                            GUIUtility.ExitGUI(); // 立即退出GUI循环，防止后续绘制问题
                        }
                    }

                    EditorGUILayout.EndScrollView();
                    EditorGUILayout.EndVertical();
                }
            }
        }

        private void ShowAllTypesMenu()
        {
            var menu = new GenericMenu();
            foreach (var typeName in s_graphModelTypeFullNames)
            {
                menu.AddItem(new GUIContent(typeName), false, () =>
                {
                    // 用户在菜单中选择了一项
                    serializedObject.Update();
                    _runtimeTypeSearchInput = typeName;
                    _runtimeTypeProp.stringValue = typeName;
                    serializedObject.ApplyModifiedProperties();
                });
            }
            menu.ShowAsContext();
        }
    }
}